"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Maintainer: 
"       Wang Yuanchuang
"       yuanchuang.wangyc@alibaba-inc.com
" Sections:
"    -> General
"    -> VIM user interface
"    -> Colors and Fonts
"    -> Files and backups
"    -> Text, tab and indent related
"    -> Visual mode related
"    -> Moving around, tabs and buffers
"    -> Status line
"    -> Editing mappings
"    -> vimgrep searching and cope displaying
"    -> Spell checking
"    -> Misc
"    -> Helper functions
"    -> Public settings and mappings
"    -> Vim search and replace
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" 
set nocompatible
set runtimepath=$VIRTUAL_RC_HOME/vim_runtime,$VIRTUAL_RC_HOME/vim_runtime/after,$VIMRUNTIME

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => General
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Sets how many lines of history VIM has to remember
set history=9216

" Enable filetype plugins
filetype plugin on
filetype indent on

" Set to auto read when a file is changed from the outside
set autoread

" Show line num
set number

" With a map leader it's possible to do extra key combinations
" like <leader>w saves the current file
let mapleader = ","
let g:mapleader = ","

" unset using map after
mapclear

" Fast saving
" nmap <leader>w :w!<cr>

vmap <Leader>n <Esc><Esc>
nmap <Leader>n <Esc><Esc>

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => VIM user interface
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set line number to the cursor - when moving vertically using j/k
set scrolloff=3

" Turn on the WiLd menu
set wildmenu

" Ignore compiled files
set wildignore=*.o,*~,*.pyc

"Always show current position
set ruler

" Height of the command bar
set cmdheight=1

" A buffer becomes hidden when it is abandoned
set hid

" Configure backspace so it acts as it should act
set backspace=eol,start,indent
" set whichwrap+=<,>,h,l
set whichwrap+=<,>

" Ignore case when searching
" set ignorecase

" When searching try to be smart about cases 
set smartcase

" Highlight search results
set hlsearch

" Makes search act like search in modern browsers
set incsearch

" Don't redraw while executing macros (good performance config)
set lazyredraw

" For regular expressions turn magic on
set magic

" Show matching brackets when text indicator is over them
set showmatch
" How many tenths of a second to blink when matching brackets
set matchtime=2

" No annoying sound on errors
set noerrorbells
set novisualbell
set t_vb=
set timeoutlen=2000
" set ttimeoutlen=-1


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Colors and Fonts
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Enable syntax highlighting
syntax enable

colorscheme desert
set background=dark

" Set extra options when running in GUI mode
if has("gui_running")
    set guioptions-=T
    set guioptions+=e
    set t_Co=256
    set guitablabel=%M\ %t
endif

" Set utf8 as standard encoding and en_US as the standard language
set encoding=utf8

" Use Unix as the standard file type
set ffs=unix,dos,mac


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Files, backups and undo
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Turn backup off, since most stuff is in SVN, git et.c anyway...
" set nobackup
" set nowb
" set noswapfile


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Text, tab and indent related
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Use spaces instead of tabs
set expandtab

" Be smart when using tabs ;)
set smarttab

" 1 tab == 4 spaces
set shiftwidth=4
set tabstop=4

" Linebreak on 500 characters
set lbr
set tw=500

set autoindent
set smartindent
set wrap "Wrap lines


""""""""""""""""""""""""""""""
" => Visual mode related
""""""""""""""""""""""""""""""
" Visual mode pressing * or # searches for the current selection
" Super useful! From an idea by Michael Naumann
" vnoremap <silent> * :call PrepareFind(GetVisualSelection(), 'gsbw', -2)<CR>
" vnoremap <silent> # :call VisualSelection('b')<CR>

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Moving around, tabs, windows and buffers
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Treat long lines as break lines (useful when moving around in them)
" map j gj
" map k gk

" Map <Space> to / (search) and Ctrl-<Space> to ? (backwards search)
" map <space> /
" map <c-space> ?

" Disable highlight when <leader><cr> is pressed
" map <silent> <leader><cr> :noh<cr>

" Smart way to move between windows
" map <C-j> <C-W>j
" map <C-k> <C-W>k
" map <C-h> <C-W>h
" map <C-l> <C-W>l

" Close the current buffer
" map <leader>bd :Bclose<cr>

" Close all the buffers
" map <leader>ba :1,1000 bd!<cr>

" Useful mappings for managing tabs
" map <leader>tn :tabnew<cr>
" map <leader>to :tabonly<cr>
" map <leader>tc :tabclose<cr>
" map <leader>tm :tabmove

" Opens a new tab with the current buffer's path
" Super useful when editing files in the same directory
" map <leader>te :tabedit <c-r>=expand("%:p:h")<cr>/

" Switch CWD to the directory of the open buffer
" map <leader>cd :cd %:p:h<cr>:pwd<cr>

" Specify the behavior when switching between buffers 
" try
    " set switchbuf=useopen,usetab,newtab
    " set stal=2
" catch
" endtry

" Return to last edit position when opening files (You want this!)
" autocmd BufReadPost *
     " \ if line("'\"") > 0 && line("'\"") <= line("$") |
     " \   exe "normal! g`\"" |
     " \ endif
" Remember info about open buffers on close
" set viminfo^=%
set viminfo='1000,<1000,s100,h

""""""""""""""""""""""""""""""
" => Status line
""""""""""""""""""""""""""""""
" Always show the status line
set laststatus=2

" Format the status line
set statusline=\ %{HasPaste()}%F%m%r%h\ %w\ \ CWD:\ %r%{getcwd()}%h\ \ \ Line:\ %l


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Editing mappings
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Remap VIM 0 to first non-blank character
" map 0 ^

" Move a line of text using ALT+[jk] or Comamnd+[jk] on mac
" nmap <M-j> mz:m+<cr>`z
" nmap <M-k> mz:m-2<cr>`z
" vmap <M-j> :m'>+<cr>`<my`>mzgv`yo`z
" vmap <M-k> :m'<-2<cr>`>my`<mzgv`yo`z

" if has("mac") || has("macunix")
    " nmap <D-j> <M-j>
    " nmap <D-k> <M-k>
    " vmap <D-j> <M-j>
    " vmap <D-k> <M-k>
" endif

" Delete trailing white space on save, useful for Python and CoffeeScript ;)
" func! DeleteTrailingWS()
    " exe "normal mz"
    " %s/\s\+$//ge
    " exe "normal `z"
" endfunc
" autocmd BufWrite *.py :call DeleteTrailingWS()
" autocmd BufWrite *.coffee :call DeleteTrailingWS()


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => vimgrep searching and cope displaying
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" When you press gv you vimgrep after the selected text
" vnoremap <silent> rv :call VisualSelection('gn')<CR>

" Open vimgrep and put the cursor in the right position
" map <leader>g :vimgrep // **/*.<left><left><left><left><left><left><left>

" Vimgreps in the current file
" map <leader><space> :vimgrep // <C-R>%<C-A><right><right><right><right><right><right><right><right><right>

" When you press <leader>r you can search and replace the selected text
" vnoremap <silent> <leader>r :call VisualSelection('replace')<CR>

" Do :help cope if you are unsure what cope is. It's super useful!
"
" When you search with vimgrep, display your results in cope by doing:
"   <leader>cc
"
" To go to the next search result do:
"   <leader>n
"
" To go to the previous search results do:
"   <leader>p
"
" map <leader>cc :botright cope<cr>
" map <leader>co ggVGy:tabnew<cr>:set syntax=qf<cr>pgg
" map <leader>n :cn<cr>
" map <leader>p :cp<cr>



"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Spell checking
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Pressing ,ss will toggle and untoggle spell checking
" map <leader>ss :setlocal spell!<cr>

" Shortcuts using <leader>
" map <leader>sn ]s
" map <leader>sp [s
" map <leader>sa zg
" map <leader>s? z=


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Misc
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Remove the Windows ^M - when the encodings gets messed up
" noremap <Leader>m mmHmt:%s/<C-V><cr>//ge<cr>'tzt'm

" Quickly open a buffer for scripbble
" map <leader>q :e ~/buffer<cr>

" Toggle paste mode on and off
" map <leader>pp :setlocal paste!<cr>


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Helper functions
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" function! CmdLine(str)
    " exe "menu Foo.Bar :" . a:str
    " emenu Foo.Bar
    " unmenu Foo
" endfunction

" function! VisualSelection(direction) range
"    let l:saved_reg = @"
"    execute "normal! vgvy"
" 
"     let l:pattern = escape(@", '\\/.*$^~[]')
"     let l:pattern = substitute(l:pattern, "\n$", "", "")
" 
"     if a:direction == 'b'
"         execute "normal ?" . l:pattern . "^M"
"     elseif a:direction == 'gv'
"         call CmdLine("vimgrep " . '/'. l:pattern . '/' . ' **/*.')
"     elseif a:direction == 'replace'
"         call CmdLine("%s" . '/'. l:pattern . '/')
"     elseif a:direction == 'f'
"         execute "normal /" . l:pattern . "^M"
"     endif
" 
"     let @/ = l:pattern
"     let @" = l:saved_reg
" endfunction

function! GetVisualSelection()
    let l:saved_reg = @"
    execute "normal! vgvy"
    let l:selection = @"
    " let @/ = escape(@", '\\/.*$^~[]')
    let @" = l:saved_reg
    return l:selection
endfunction

" flag: s,w
function! ExecuteFind(selection, flag)
    let l:command = ""
    if a:selection != ""
        let l:case_sensitive = match(a:flag, "s")
        let l:pattern = escape(a:selection, '\\/.*$^~[]')
        if match(a:flag, "w") != -1
            let l:pattern = "\\<" . l:pattern . "\\>"
        endif
        let @/ = l:pattern
        if l:case_sensitive != -1
            let l:command = "vimgrep " . "/\\C" . l:pattern . "/gj " . @%
        else
            let l:command = "vimgrep " . "/\\c" . l:pattern . "/gj " . @%
        endif
    endif
    execute "menu Execute.Bar :" . l:command
    emenu Execute.Bar
    unmenu Execute
endfunction

" > 0, from the begin offset; from the end offset
function! PrepareFind(selection, flag, offset)
    let l:offset_cmd = ""
    if a:offset > 0
        let l:offset_cmd = "<Home>"
        for i in range(a:offset)
            let l:offset_cmd .= "<Right>"
        endfor
    elseif a:offset < 0
        for i in range(-a:offset)
            let l:offset_cmd .= "<Left>"
        endfor
    else
    endif
    let l:commond = "call ExecuteFind(\'" . a:selection . "\', \'" . a:flag . "\')" . l:offset_cmd
    execute "menu Prepare.Bar :" . l:commond
    emenu Prepare.Bar
    unmenu Prepare
endfunction

" flag: s,c,w
function! ExecuteReplace(from, to, flag)
    let l:command = ""
    if a:from != ""
        let l:case_sensitive = match(a:flag, "s")
        let l:pattern = escape(a:from, '\\/.*$^~[]')
        let l:content = escape(a:to, '\\/.*$^~[]')
        if match(a:flag, "w") != -1
            let l:pattern = "\\<" . l:pattern . "\\>"
        endif
        let @/ = l:pattern
        let l:command_flag = ""
        if -1 == match(a:flag, "s")
            let l:command_flag .= "i"
        endif
        if match(a:flag, "c") != -1
            let l:command_flag .= "c"
        endif
        let l:command_flag .= "eg"
        let l:command = "%s/" . l:pattern . "/" . l:content . "/" . l:command_flag
    endif
    execute "menu Execute.Bar :" . l:command
    emenu Execute.Bar
    unmenu Execute
endfunction

function! PrepareReplace(from, to, flag, offset)
    let l:offset_cmd = ""
    if a:offset > 0
        let l:offset_cmd = "<Home>"
        for i in range(a:offset)
            let l:offset_cmd .= "<Right>"
        endfor
    elseif a:offset < 0
        for i in range(-a:offset)
            let l:offset_cmd .= "<Left>"
        endfor
    else
    endif
    let l:commond = "call ExecuteReplace(\'" . a:from . "\', \'". a:to . "\', \'" . a:flag . "\')" . l:offset_cmd
    execute "menu Prepare.Bar :" . l:commond
    emenu Prepare.Bar
    unmenu Prepare
endfunction

" Returns true if paste mode is enabled
function! HasPaste()
    if &paste
        return 'PASTE MODE  '
    en
    return ''
endfunction

" Don't close window, when deleting a buffer
" command! Bclose call <SID>BufcloseCloseIt()
" function! <SID>BufcloseCloseIt()
    " let l:currentBufNum = bufnr("%")
    " let l:alternateBufNum = bufnr("#")

    " if buflisted(l:alternateBufNum)
        " buffer #
    " else
        " bnext
    " endif

    " if bufnr("%") == l:currentBufNum
        " new
    " endif

    " if buflisted(l:currentBufNum)
        " execute("bdelete! ".l:currentBufNum)
    " endif
" endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Public settings and mappings
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" NERDTree
let NERDTreeQuitOnOpen=1
let NERDTreeWinSize=36
let NERDTreeShowLineNumbers=1
let NERDTreeDirArrows=0
let NERDTreeMinimalUI=1

" MRU
let MRU_Max_Entries=256
let MRU_Window_Height=30
let MRU_Auto_Close=1
let MRU_File=$VIRTUAL_RC_HOME . "/vim.mru"
" let MRU_Exclude_Files='\.txt$\|\.vim$'

" quickfix
nmap <F4> :cnext<CR>
nmap <F3> :cprevious<CR>
nmap <Leader>db :crewind<CR>

" Window move
nmap <Leader>h <C-W>h
nmap <Leader>j <C-W>j
nmap <Leader>k <C-W>k
nmap <Leader>l <C-W>l

" Window open/close
nmap <Leader>dv :copen<CR>
nmap <Leader>dc :cclose<CR>
nmap <Leader>dt :NERDTreeToggle<CR>
nmap <Leader>da :NERDTreeFind<CR>
nmap <Leader>de :BufExplorer<CR>
nmap <Leader>dr :MRU<CR>

" File edit
nmap <Leader>q :q<CR>
nmap <Leader>w :w<CR>
nmap <Leader>x :x<CR>
nmap <Leader>eq :qall<CR>
nmap <Leader>ew :wall<CR>
nmap <Leader>ex :wall!<CR>:qall<CR>
nmap <Leader>ed :q!<CR>
nmap <Leader>ec :qall!<CR>
nmap <Leader>es <C-Z>

" Misc
map <F5> <Esc><C-O>
map <F6> <Esc><C-I>

" visual mode map
vmap <Leader>y "zy
vmap <Leader>r c<C-O>"zP<Esc>
vmap <Leader>d "zd<Esc>

" normal mode map
nmap <Leader>c "zyiw
nmap <Leader>p "zp
nmap <Leader>v "zP
nmap <Leader>r ciw<Esc>"zp

" insert mode map
imap <C-B> <Esc>
imap <C-C> <Nop>
imap <C-E> <Nop>
imap <C-F> <Nop>
imap <C-L> <Nop>
imap <C-Y> <Nop>
" insert mode highlight keyword
imap <C-E>g <Esc><Leader>ega
imap <C-F>g <Esc><Leader>ga
imap <C-F>x <Esc><Leader>mxa
" insert mode quit and save
imap <C-E>w <Esc>:w<Cr>a
imap <C-E>q <Esc>:q<Cr>
imap <C-E>x <Esc>:x<Cr>
imap <C-E>d <Esc>:q!<Cr>
" insert mode new line
imap <C-E>a <C-O>$<Cr>
" insert mode undo and redo
imap <C-E>u <C-O>u
imap <C-E>r <C-O><C-R>
" insert mode copy
imap <C-F>c <C-O>"zyiw
imap <C-F>d <C-O>"zyy
" insert mode paste
imap <C-F>p <C-O>"zp
imap <C-F>v <Esc>"zpa
imap <C-F>r <C-O>diw<C-O>"zP
" insert mode delete
imap <C-E>o <C-O>d0
imap <C-E>f <C-O>d^
imap <C-E>s <C-O>d$
imap <C-E>e <C-O>de
imap <C-E>` <C-O>dt`
imap <C-E>~ <C-O>dt~
imap <C-E>! <C-O>dt!
imap <C-E>@ <C-O>dt@
imap <C-E># <C-O>dt#
imap <C-E>$ <C-O>dt$
imap <C-E>% <C-O>dt%
imap <C-E>^ <C-O>dt^
imap <C-E>& <C-O>dt&
imap <C-E>* <C-O>dt*
imap <C-E>( <C-O>dt(
imap <C-E>) <C-O>dt)
imap <C-E>- <C-O>dt-
imap <C-E>_ <C-O>dt_
imap <C-E>= <C-O>dt=
imap <C-E>+ <C-O>dt+
imap <C-E>[ <C-O>dt[
imap <C-E>{ <C-O>dt{
imap <C-E>] <C-O>dt]
imap <C-E>} <C-O>dt}
imap <C-E>\ <C-O>dt\
imap <C-E>\| <C-O>dt\|
imap <C-E>; <C-O>dt;
imap <C-E>: <C-O>dt:
imap <C-E>' <C-O>dt'
imap <C-E>" <C-O>dt"
imap <C-E>, <C-O>dt,
imap <C-E>< <C-O>dt<
imap <C-E>. <C-O>dt.
imap <C-E>> <C-O>dt>
imap <C-E>/ <C-O>dt/
imap <C-E>? <C-O>dt?
" insert mode move
imap <C-F>h <C-O>h
imap <C-F>j <C-O>j
imap <C-F>k <C-O>k
imap <C-F>l <C-O>l
imap <C-F>o <Home>
imap <C-F>f <C-O>^
imap <C-F>s <C-O>$
imap <C-F>b <C-O>b
imap <C-F>e <C-O>e
imap <C-F>w <C-O>w
imap <C-F>` <C-O>f`
imap <C-F>~ <C-O>f~
imap <C-F>! <C-O>f!
imap <C-F>@ <C-O>f@
imap <C-F># <C-O>f#
imap <C-F>$ <C-O>f$
imap <C-F>% <C-O>f%
imap <C-F>^ <C-O>f^
imap <C-F>& <C-O>f&
imap <C-F>* <C-O>f*
imap <C-F>( <C-O>f(
imap <C-F>) <C-O>f)
imap <C-F>- <C-O>f-
imap <C-F>_ <C-O>f_
imap <C-F>= <C-O>f=
imap <C-F>+ <C-O>f+
imap <C-F>[ <C-O>f[
imap <C-F>{ <C-O>f{
imap <C-F>] <C-O>f]
imap <C-F>} <C-O>f}
imap <C-F>\ <C-O>f\
imap <C-F>\| <C-O>f\|
imap <C-F>; <C-O>f;
imap <C-F>: <C-O>f:
imap <C-F>' <C-O>f'
imap <C-F>" <C-O>f"
imap <C-F>, <C-O>f,
imap <C-F>< <C-O>f<
imap <C-F>. <C-O>f.
imap <C-F>> <C-O>f>
imap <C-F>/ <C-O>f/
imap <C-F>? <C-O>f?

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Vim search and replace
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
vmap <Leader>mg :call PrepareFind(GetVisualSelection(), 'sw', -2)<CR>
nmap <Leader>mg :call PrepareFind('', 'sw', 18)<CR>
nmap <Leader>mw :call PrepareFind(expand("<cword>"), 'sw', -2)<CR>
nmap <silent> <Leader>mm :call PrepareFind(expand("<cword>"), 'sw', 0)<CR><CR><CR>
nmap <silent> <Leader>mj :call PrepareFind(expand("<cword>"), 'sw', 0)<CR><CR><CR>:crewind<CR>
vmap <Leader>mr :call PrepareReplace(GetVisualSelection(), '', 'scw', -9)<CR>
nmap <Leader>mr :call PrepareReplace('', '', 'scw', 21)<CR>
nmap <Leader>ms :call PrepareReplace(expand("<cword>"), '', 'scw', -9)<CR>

